// Copyright (C) 2009 Jesse Jones
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using MmmDoc;
using Mono.Cecil;

namespace MmmDoc.Database
{
	/// <summary>Argument list used by <see cref = "Database.Member"/>.</summary>
	internal sealed class Arguments
	{
		public Arguments(Document doc, MethodDefinition member)
		{
			Opener = "(";
			Modifiers = new string[member.Parameters.Count];
			Types = new TypeName[member.Parameters.Count];
			Names = new string[member.Parameters.Count];
			Closer = ")";
			
			for (int i = 0; i < member.Parameters.Count; ++i)
			{
				ParameterDefinition p = member.Parameters[i];
				
				Modifiers[i] = DoGetModifier(member, i);
				Types[i] = TypeName.Create(doc, p.ParameterType);
				Names[i] = p.Name;
			}
		}
		
		public Arguments(Document doc, PropertyDefinition member)
		{
			Opener = "[";
			Modifiers = new string[member.Parameters.Count];
			Types = new TypeName[member.Parameters.Count];
			Names = new string[member.Parameters.Count];
			Closer = "]";
			
			for (int i = 0; i < member.Parameters.Count; ++i)
			{
				ParameterDefinition p = member.Parameters[i];
				
				Modifiers[i] = null;
				Types[i] = TypeName.Create(doc, p.ParameterType);
				Names[i] = p.Name;
			}
		}
		
		/// <summary>Text used to open the arguments. Usually &quot;(&quot;.</summary>
		public string Opener {get; private set;}
		
		/// <summary>&quot;Ref&quot;, &quot;out&quot;, or &quot;this&quot;.</summary>
		/// <remarks>Null if the type has no modifier.</remarks>
		public string[] Modifiers {get; private set;}
		
		/// <summary>Returns the types for each argument.</summary>
		public TypeName[] Types {get; private set;}
		
		/// <summary>Returns the names for each argument.</summary>
		public string[] Names {get; private set;}
		
		/// <summary>Text used to close the arguments. Usually &quot;)&quot;.</summary>
		public string Closer {get; private set;}
		
//		public string this[int index]
//		{
//			get {return Names[index];}
//		}
		
		#region Private Methods
		private string DoGetModifier(MethodDefinition method, int i)
		{
			var builder = new System.Text.StringBuilder();
			
			if (i == 0 && method.HasCustomAttributes && method.CustomAttributes.HasAttribute("System.Runtime.CompilerServices.ExtensionAttribute"))
				builder.Append("this ");
			
			ParameterDefinition p = method.Parameters[i];
			if (p.HasCustomAttributes && p.CustomAttributes.HasAttribute("System.ParamArrayAttribute"))
				builder.Append("params ");
			
			string typeName = p.ParameterType.FullName;
			if (typeName.EndsWith("&"))
			{
				if (p.IsOut)
					builder.Append("out ");
				else
					builder.Append("ref ");
			}
			
			return builder.ToString();
		}
		#endregion
	}
}
